/*
 * Copyright (c) 2024 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef OBJECT_H
#define OBJECT_H
#include <core/atomic.h>
#include <core/spinlock.h>
#include <core/dprintf.h>

extern int allocator_free(unsigned long begin, unsigned int size);

typedef struct ob__object {
    atomic_t   refcount;
    spinlock_t lock;
} object_t;

static inline int object_get(object_t *obj)
{
    return atomic_add(&obj->refcount, 1);
}

static inline int object_put(object_t *obj, unsigned int offset, unsigned int size)
{
    int ret = atomic_sub(&obj->refcount, 1);
    if ((ret == 0) && ((size == 0U) || (allocator_free((unsigned long)obj - offset, size) != 0))) {
        dprintf("Memory leaked at %x, total %d bytes!\n", (unsigned long)obj - offset, size);
    }

    return ret;
}

static inline int object_refcount(object_t *obj)
{
    return atomic_load(&obj->refcount);
}

static inline void object_lock(object_t *obj)
{
    spin_lock(&obj->lock);
}

static inline void object_unlock(object_t *obj)
{
    spin_unlock(&obj->lock);
}

static inline int object_try_lock(object_t *obj)
{
    return spin_try_lock(&obj->lock);
}

static inline void object_init(object_t *obj)
{
    spin_init_unlocked(&obj->lock);
    (void)atomic_store(&obj->refcount, 0);
}

#endif
